package cageballtv;

import cageballcommon.messages.Player;
import cageballcommon.messages.State;
import java.awt.Color;
import java.awt.Frame;
import java.awt.Graphics2D;
import java.awt.Toolkit;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferStrategy;

import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;

public class Visualizer implements Runnable {

    protected Frame frame;
    protected String title;
    private boolean running = true;
    private BufferStrategy strategy;
    private int fieldLengthY;
    private int fieldLengthX;
    private int goalSize;
    private StateReceiver stateReceiver;
    private Properties properties;
    private int ballRadius;
    private int playerRadius;
    private int postRadius;
    private int matchLength;
    private Color ballColor = Color.LIGHT_GRAY;
    private Color team1PlayerColor = Color.ORANGE;
    private Color team2PlayerColor = Color.CYAN;
    private Color team1TextColor = Color.BLACK;
    private Color team2TextColor = Color.BLACK;
    private Color textColor = Color.WHITE;
    private Color lineColor = Color.WHITE;
    private Color postColor = Color.WHITE;
    private Color fieldColor = new Color(0, 110, 0);
    private int stateDelay;

    public Visualizer(StateReceiver stateReceiver) {
        this.title = "CageBallTV";
        this.stateReceiver = stateReceiver;
    }

    private void initGUI() {
        frame = new Frame(title);
        frame.setResizable(false);
        frame.setIgnoreRepaint(true);

        frame.setSize((int) fieldLengthX, (int) fieldLengthY);

        int x = (int) (Toolkit.getDefaultToolkit().getScreenSize().getWidth() - (int) fieldLengthX) / 2;
        int y = (int) (Toolkit.getDefaultToolkit().getScreenSize().getHeight() - (int) fieldLengthY) / 2;

        frame.setLocation(x, y);

        frame.addWindowListener(new WindowAdapter() {

            public void windowClosing(WindowEvent e) {
                running = false;
                System.exit(0);
            }
        });
        frame.addKeyListener(new KeyAdapter() {

            public void keyPressed(KeyEvent e) {
                if (e.getKeyCode() == 27) {
                    System.exit(0);
                }
            }
        });

        frame.setVisible(true);
        frame.createBufferStrategy(2);


        strategy = frame.getBufferStrategy();
    }

    private void drawCircle(Graphics2D g, int x, int y, int r, Color color) {
        g.setColor(color);
        g.fillOval((int) (x - r), (int) (y - r), (int) (r * 2), (int) (r * 2));
    }

    public void run() {

        try {

            while (running) {
                stateReceiver.init();

                if (frame != null) {
                    frame.setVisible(false);
                    frame.dispose();
                }

                properties = stateReceiver.getProperties();
                fieldLengthX = Integer.parseInt(properties.getProperty("fieldLengthX"));
                fieldLengthY = Integer.parseInt(properties.getProperty("fieldLengthY"));
                goalSize = Integer.parseInt(properties.getProperty("goalSize"));
                ballRadius = Integer.parseInt(properties.getProperty("ballSize"));
                playerRadius = Integer.parseInt(properties.getProperty("playerSize"));
                postRadius = Integer.parseInt(properties.getProperty("postSize"));

                matchLength = Integer.parseInt(properties.getProperty("matchLength"));
                stateDelay = Integer.parseInt(properties.getProperty("stateDelay"));


                initGUI();

                int width = fieldLengthX / 8;
                int height = fieldLengthY * 4 / 7;
                int lineThickness = 6;

                while (running) {

                    State state = stateReceiver.getNextState();

                    if (state.getInfo() != null) {
                        if (state.getInfo().getWinner() != null) {
                            break;
                        }
                    }

                    Graphics2D g = (Graphics2D) strategy.getDrawGraphics();
                    g.setColor(fieldColor);
                    g.fillRect(0, 0, (int) fieldLengthX, (int) fieldLengthY);

                    g.setColor(lineColor);
                    /* Upper left part of the goal-circle */
                    g.fillRect(0, (int) (fieldLengthY / 2 - height / 2) - lineThickness, width, lineThickness);
                    /* Lower left part of the goal-circle */
                    g.fillRect(0, (int) (fieldLengthY / 2 + height / 2), width, lineThickness);
                    /* Middle left part of the goal-circle */
                    g.fillRect(width, (int) (fieldLengthY / 2 - height / 2) - lineThickness, lineThickness, height + lineThickness * 2);
                    /* Upper right part of the goal-circle */
                    g.fillRect(fieldLengthX - width, (int) (fieldLengthY / 2 - height / 2) - lineThickness, width, lineThickness);
                    /* Lower right part of the goal-circle */
                    g.fillRect(fieldLengthX - width, (int) (fieldLengthY / 2 + height / 2), width, lineThickness);
                    /* Middle right part of the goal-circle */
                    g.fillRect(fieldLengthX - width - lineThickness, (int) (fieldLengthY / 2 - height / 2) - lineThickness, lineThickness, height + lineThickness * 2);
                    /* Mid-line */
                    g.fillRect(fieldLengthX / 2 - lineThickness / 2, 0, lineThickness, fieldLengthY);

                    drawCircle(g, 0, (fieldLengthY - goalSize) / 2, postRadius, postColor);
                    drawCircle(g, 0, fieldLengthY - (fieldLengthY - goalSize) / 2, postRadius, postColor);
                    drawCircle(g, fieldLengthX, (fieldLengthY - goalSize) / 2, postRadius, postColor);
                    drawCircle(g, fieldLengthX, fieldLengthY - (fieldLengthY - goalSize) / 2, postRadius, postColor);
                    drawCircle(g, (int) state.getBall().getX(), (int) state.getBall().getY(), ballRadius, ballColor);

                    for (Player p : state.getMyTeam().getPlayers()) {
                        drawCircle(g, (int) p.getX() + 2, (int) p.getY() - 5, playerRadius, team1PlayerColor);
                        g.setColor(team1TextColor);
                        g.drawString(new Integer(p.getId()).toString(), (int) p.getX(), (int) p.getY());
                    }

                    for (Player p : state.getOtherTeam().getPlayers()) {
                        drawCircle(g, (int) p.getX() + 2, (int) p.getY() - 5, playerRadius, team2PlayerColor);
                        g.setColor(team2TextColor);
                        g.drawString(new Integer(p.getId()).toString(), (int) p.getX(), (int) p.getY());

                    }

                    g.setColor(textColor);
                    g.drawString("Time: " + state.getTime() + " / " + matchLength, 10, 40);
                    g.drawString(stateReceiver.getTeam1().getTeamName() + " vs " + stateReceiver.getTeam2().getTeamName() + " (" + state.getMyTeam().getScore() + " - " + state.getOtherTeam().getScore() + ")", 10, 60);
                    g.dispose();
                    strategy.show();

                    Thread.sleep(stateDelay);

                }
            }
        } catch (InterruptedException ex) {
            Logger.getLogger(Visualizer.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}
